Use authorization code flow with PKCE when a client secret is specified#67
Conversation
zentron
left a comment
There was a problem hiding this comment.
Couple little requests around code cleanup and a rename of the SessionId to RequestId but otherwise its looking pretty good.
| var stateFromRequest = JsonConvert.DeserializeObject<LoginStateWithSessionId>(state); | ||
| var response = await RequestAuthToken(code, redirectUri, stateFromRequest!.SessionId); | ||
|
|
||
| // Step 1: Try and get all of the details from the request making sure there are no errors passed back from the external identity provider |
There was a problem hiding this comment.
Im guessing this is a bit of C+P from what was in the original UserAuthenticatedAction method. is there anything here that we have in common that can be extracted out?
| return loginFailed.Response(message); | ||
| } | ||
|
|
||
| IResultFromExtension<IUser> GetOrCreateUser(UserResource userResource, string[] groups, CancellationToken cancellationToken) |
There was a problem hiding this comment.
Again, is there much in here which is really different from the existing class?
|
|
||
| namespace Octopus.Server.Extensibility.Authentication.OpenIDConnect.Common.Web | ||
| { | ||
| public class AuthServerResponseHandler<TAuthTokenHandler> where TAuthTokenHandler : IAuthTokenHandler |
There was a problem hiding this comment.
Technically this either handles a request (in the case of the implicit flow) or a response (in the case of auth code flow) from the auth server but I went with naming it ResponseHandler.
|
|
||
| public async Task<ClaimsPrincipalContainer> GetDetailsFromRequestEnsuringNoErrors(IDictionary<string, string?> requestForm) | ||
| { | ||
| var principalContainer = await authTokenHandler.GetPrincipalAsync(requestForm, out _); |
There was a problem hiding this comment.
No longer use the out var for the state - could also remove it from the method itself?
| var octoResponse = UserAuthenticatedValidator.Redirect.Response(state.RedirectAfterLoginTo) | ||
| .WithHeader("Expires", new[] { DateTime.UtcNow.AddYears(1).ToString("R", DateTimeFormatInfo.InvariantInfo) }) | ||
| .WithCookie(new OctoCookie(UserAuthConstants.OctopusStateCookieName, Guid.NewGuid().ToString()) { HttpOnly = true, Secure = false, Expires = DateTimeOffset.MinValue }) | ||
| .WithCookie(new OctoCookie(UserAuthConstants.OctopusNonceCookieName, Guid.NewGuid().ToString()) {HttpOnly = true, Secure = false, Expires = DateTimeOffset.MinValue}); |
There was a problem hiding this comment.
I'm guessing setting these cookies just resets them to some value so they can't be re-used?
|
|
||
| public async Task<IOctoResponseProvider> ExecuteAsync(IOctoRequest request) | ||
| { | ||
| // Step 1: Try and get all of the details from the request making sure there are no errors passed back from the external identity provider |
There was a problem hiding this comment.
I removed all the comments. I think some of the method names are very clear, others maybe it would be useful to keep the comment?
| { | ||
| await mediator.Do( | ||
| new PutBlobCommand(ConfigurationStore.ConfigurationSettingsName, requestId, JsonSerializer.SerializeToUtf8Bytes(blob)), | ||
| new CancellationToken()); |
There was a problem hiding this comment.
Is new CancellationToken ok here?
There was a problem hiding this comment.
I cant see many places where we might already have a token so could you perhaps just wrap the code as high as it makes sense with a
using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(1));
and pass it around where necessary
zentron
left a comment
There was a problem hiding this comment.
Minor comment around the cancellation token but once that is fixed and this all still works then feel free to merge :)
Thanks for the additional time spent 👍
| { | ||
| await mediator.Do( | ||
| new PutBlobCommand(ConfigurationStore.ConfigurationSettingsName, requestId, JsonSerializer.SerializeToUtf8Bytes(blob)), | ||
| new CancellationToken()); |
There was a problem hiding this comment.
I cant see many places where we might already have a token so could you perhaps just wrap the code as high as it makes sense with a
using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(1));
and pass it around where necessary
Relates to OctopusDeploy/Issues#7141
Manually tested with:
Also comes with some docs changes OctopusDeploy/docs#1496
Testing
Terraform files for creating an app registration in Okta are available on the nelson/terraform branch. You can follow the instructions in our docs for creating a dev Okta instance.
The variables are:
org_name-> The name of the instance eg.dev-3219475(don't need to add-admin)api_token-> The API token generated inSecurity -> APIin the Okta portalredirect_uri-> Would behttp://localhost:8065/api/users/authenticatedToken/Oktaon a default local server instance